package com.serviceprovider.business.module.order.controller;

//~--- non-JDK imports --------------------------------------------------------

import com.serviceprovider.business.module.admin.role.model.Role;
import com.serviceprovider.business.module.admin.role.services.dao.interfaces.IRoleService;
import com.serviceprovider.business.module.admin.settings.services.ISettingsService;
import com.serviceprovider.business.module.admin.shipping.model.ShipMode;
import com.serviceprovider.business.module.admin.shipping.services.dao.interfaces.IShipMode;
import com.serviceprovider.business.module.admin.user.services.dao.interfaces.IUserService;
import com.serviceprovider.business.module.order.model.EditOrderForm;
import com.serviceprovider.business.module.order.model.Order;
import com.serviceprovider.business.module.order.services.interfaces.IOrderService;
import com.serviceprovider.business.module.order.services.interfaces.IOrderStatusService;
import com.serviceprovider.business.module.order.valueobjects.OrderVO;
import com.serviceprovider.business.module.report.valueobjects.BatchVO;
import com.serviceprovider.business.module.report.valueobjects.PlaceOrderVO;
import com.serviceprovider.business.module.sp.preferences.dao.interfaces.IPreferencesDao;
import com.serviceprovider.business.module.sp.transaction.services.interfaces.ITransactionService;
import com.serviceprovider.business.utility.AppUtil;
import com.serviceprovider.business.utility.Int2DoublePropertyEditor;
import com.serviceprovider.business.utility.RequestConstants;
import com.serviceprovider.business.utility.SecurityContextUser;
import com.serviceprovider.business.utility.maintenance.interfaces.IBatchService;
import com.serviceprovider.business.utility.maintenance.settings.RoleUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

//~--- JDK imports ------------------------------------------------------------

import java.beans.PropertyEditor;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpSession;

@Controller
public class EditOrderController {
    protected final Log         logger = LogFactory.getLog(getClass());
    @Autowired
    private IBatchService       batchService;
    @Autowired
    private IOrderService       orderService;
    @Autowired
    private IOrderStatusService orderStatusService;
    @Autowired
    IPreferencesDao             preferencesService;
    @Autowired
    ISettingsService            propertiesService;
    @Autowired
    private IRoleService        roleService;
    @Autowired
    IShipMode                   shipModeService;
    @Autowired
    ITransactionService         transactionService;
    @Autowired
    IUserService                userService;
    @Autowired()
    @Qualifier("validator")
    private Validator           validator;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        PropertyEditor propertyEditorNullIsZero = new Int2DoublePropertyEditor(true);

        binder.registerCustomEditor(Integer.class, "batchList.transactions.amount", propertyEditorNullIsZero);
        binder.registerCustomEditor(Integer.class, "batchList.transactions.selfFee", propertyEditorNullIsZero);
        binder.registerCustomEditor(Integer.class, "batchList.transactions.serviceFee", propertyEditorNullIsZero);
        binder.registerCustomEditor(Integer.class, "batchList.transactions.customerBalance", propertyEditorNullIsZero);
        binder.registerCustomEditor(Integer.class, "batchList.transactions.amounts", propertyEditorNullIsZero);
        logger.debug("initBinder finished");
    }

    @ModelAttribute("shippingList")
    public List<ShipMode> getShippingList() {
        return shipModeService.list();
    }

    @ModelAttribute("isAdmin")
    public Boolean isAdmin() {
        return SecurityContextUser.isAdmin();
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.ADMIN_ORDER,
        method = RequestMethod.GET
    )
    public ModelAndView viewOrderForm(@RequestParam("orderId") Integer orderId) {
        ModelAndView  result    = new ModelAndView(RequestConstants.OrderRequests.VIEW_EDIT_ADMIN_ORDER);
        OrderVO       order     = new OrderVO(orderService.findOrderById(orderId));
        List<BatchVO> batchList = batchService.getBatchListByOrderId(orderId);

        order.setBatchList(batchList);

        EditOrderForm editOrderForm = new EditOrderForm();

        editOrderForm.setSavedOrderId(order.getId());
        result.addObject("batchVOList", batchList);
        result.addObject("orderStatusList", orderStatusService.findAll());

        Role adminRole = roleService.getRoleByName(RoleUtils.ROLE_ADMINISTRATOR);

        result.addObject("userList", userService.findByRole(adminRole));
        result.addObject("order", order);
        result.addObject("editOrderForm", editOrderForm);

        return result;
    }

    /**
     * This method will show the service provider's orders.
     *
     * @param orderId order id.
     * @return
     */
    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_ORDER,
        method = RequestMethod.GET
    )
    public ModelAndView viewOrderFormForServiceProvider(@RequestParam("orderId") Integer orderId) {
        return viewOrderForm(orderId);
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.ADMIN_ORDER,
        method = RequestMethod.POST
    )
    public ModelAndView saveOrder(@ModelAttribute("editOrderForm") EditOrderForm form) {
        ModelAndView result = new ModelAndView(RequestConstants.OrderRequests.VIEW_EDIT_ADMIN_ORDER);

        orderService.saveOrderComments(form.getComment(), form.getSavedOrderId());

        OrderVO       order         = new OrderVO(orderService.findOrderById(form.getSavedOrderId()));
        EditOrderForm editOrderForm = new EditOrderForm();

        editOrderForm.setSavedOrderId(order.getId());
        result.addObject("batchVOList", order.getBatchList());
        result.addObject("order", order);
        result.addObject("editOrderForm", editOrderForm);
        result.addObject("orderStatusList", orderStatusService.findAll());

        Role adminRole = roleService.getRoleByName(RoleUtils.ROLE_ADMINISTRATOR);

        result.addObject("userList", userService.findByRole(adminRole));

        return result;
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.UPDATE_STATUS,
        method = RequestMethod.GET
    )
    public ModelAndView updateOrderStatus(@RequestParam("id") Integer orderId,
            @RequestParam("orderStatusId") Integer orderStatusId) {
        orderService.updateStatus(orderId, orderStatusId);

        return viewOrderForm(orderId);
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.UPDATE_USER_ID,
        method = RequestMethod.GET
    )
    public ModelAndView updateAssignedUserIds(@RequestParam("id") Integer orderId,
            @RequestParam("assignedUserId") Integer assignedUserId) {
        orderService.updateAssignedUserIds(orderId, assignedUserId);

        return viewOrderForm(orderId);
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_PLACE_ORDER,
        method = RequestMethod.GET
    )
    public ModelAndView placeOrderGet() {
        Integer       spId         = userService.getUserConnected().getId();
        ModelAndView  mav          = new ModelAndView(RequestConstants.OrderRequests.VIEW_SP_PLACE_ORDER);
        List<BatchVO> batchList    = batchService.getBatchListToPlaceOrder(null);
        PlaceOrderVO  placeOrderVO = new PlaceOrderVO();

        placeOrderVO.setBatchVOList(batchList);
        placeOrderVO.setOrderName(AppUtil.getDefaultOrderName());

        // TODO: [Performance] should use count method
        placeOrderVO.setHasNewTransactions(transactionService.findNewTransactions(spId).size() != 0);
        mav.addObject("placeOrderVO", placeOrderVO);

        return mav;
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_ORDER_DETAILS,
        method = RequestMethod.GET
    )
    public ModelAndView shipOrderGet(HttpSession sess) {
        ModelAndView mav = new ModelAndView(RequestConstants.OrderRequests.VIEW_SP_ORDER_DETAILS);

        mav.addObject("orderVO", sess.getAttribute("orderVO"));

        return mav;
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_PLACE_ORDER,
        method = RequestMethod.POST
    )
    public ModelAndView orderPost(@ModelAttribute("placeOrderVO") PlaceOrderVO placeOrderVO, BindingResult result) {
        validator.validate(placeOrderVO, result);

        if (result.hasErrors()) {
            ModelAndView mav = new ModelAndView(RequestConstants.OrderRequests.VIEW_SP_PLACE_ORDER);

            mav.addObject("placeOrderVO", placeOrderVO);

            return mav;
        }

        Order   order = new Order();
        Integer spId  = userService.getUserConnected().getId();

        order.setName(placeOrderVO.getOrderName());
        order.setServiceProviderId(spId);
        order.setMode(placeOrderVO.getShippingMode());
        order.setTips(placeOrderVO.getShippingTips());
        order.setInstructions(placeOrderVO.getShippingInstructions());
        order.setOrderStatus(orderStatusService.get(1));    // New Order

        List<Integer> batchIds = new ArrayList<Integer>();

        for (BatchVO item : placeOrderVO.getBatchList()) {
            if (item.getIncludedInOrder()) {
                batchIds.add(item.getId());
            }
        }

        List<BatchVO> batchList = batchService.getBatchListToPlaceOrder(batchIds);

        orderService.insertOrder(order);

        for (BatchVO batchVO : batchList) {
            batchService.setOrderId(batchVO, order.getId());
        }

        return new ModelAndView("redirect:" + RequestConstants.OrderRequests.SP_PLACE_ORDER_RESULT);
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_PLACE_ORDER,
        method = RequestMethod.POST,
        params = "revert_transactions"
    )
    public String revertTransactionsToNew(@ModelAttribute("placeOrderVO") PlaceOrderVO placeOrderVO) {
        List<Integer> batchList = new ArrayList<Integer>();

        for (BatchVO batch : placeOrderVO.getBatchList()) {
            if (batch.getIncludedInOrder()) {
                batchList.add(batch.getId());
            }
        }

        transactionService.moveTransactionsToNew(batchList);

        return "redirect:" + RequestConstants.OrderRequests.TRANSACTION_STEP1;
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_PLACE_ORDER,
        method = RequestMethod.POST,
        params = "back_to_new_transaction"
    )
    public String backToNewTransaction() {
        return "redirect:" + RequestConstants.TransactionRequests.SP_NEW_TRANSACTION;

        // return "redirect:/provider/new.htm";
    }

    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_PLACE_ORDER_RESULT,
        method = RequestMethod.GET
    )
    public ModelAndView viewOrderPlacingResult() {
        return new ModelAndView(RequestConstants.OrderRequests.VIEW_SP_PLACE_ORDER_RESULT);
    }
}



